Go 语言学习-包管理
Golang 的包管理
每一个 Go 语言程序都必须是一些包的一部分。一个独立 可执行的 Go 语言程序必须有 package main
声明。如果一个程序是 main 包的一部分,那么在 go install
则会生成一个二进制文件,在执行时则会调用 main 函数。
go install
命令在编译源代码之后还安装到指定的目录,即:go build
命令 + 把编译后的可执行文件放到GOPATH/bin
目录下
如果一个程序除了 main 包外还是其他包的一部分,那么在使用 go install
命令时会创建包存档文件。
配置环境
Linux 配置环境变量
$ vim ~/.bashrc
# 设置语言路径
export GOROOT=/usr/local/go # 表示源码包路径
export GOPATH=$HOME/go # 开发者 Go 的项目默认路径,一般不用
export PATH=$PATH:$GOROOT/bin:$GOPATH/bin
$ source ~/.bashrc # 使配置文件生效
设置下载代理
# 例如这里设置为 C:\Users\33204\go
go env -w GOPATH=我们自己的工作区路径
# 设置代理服务器(在 GitHub 下载工具)
go env -w GO111MODULE=on
# 这个 direct 表示前面的代理找不到则回源地址去找
go env -w GOPROXY=https://goproxy.cn,direct
检查 Go 的环境变量
go env
Go Modules 是什么?
GoMOD 就是 Go 的 Maven,用于管理依赖,go mod
是 Golang 1.11 版本引入的官方包(package)依赖管理工具,用于解决之前没有地方记录依赖包具体版本的问题,方便依赖包的管理。
使用起来也非常简单,常用命令就一个 go mod tidy
,通俗来说就是将当前的库源码文件所依赖的包,全部安装并记录下来,多的包就删掉,少了的就自动补上
Golang 提供一个环境变量 GO111MODULE 来设置是否使用 mod,它有3个可选值,分别是 off, on, auto
(默认值),具体含义如下:
- off:GOPATH mode,查找 vendor 和 GOPATH 目录
- on:module-aware mode,即使用
go module
,忽略 GOPATH 目录 - auto:如果当前目录不在
$GOPATH
并且 当前目录(或者父目录)下有go.mod
文件,则使用 GO111MODULE, 否则仍旧使用 GOPATH mode。
修改 GO111MODULE 的值的语句是:set GO111MODULE=on
。
在使用模块的时候, GOPATH 是无意义的,不过它还是会把下载的依赖储存在 GOPATH/src/mod 中,也会把 go install
的结果放在 GOPATH/bin(如果 GOBIN 不存在的话)
go.mod 文件
Go.mod 是 Golang1.11 版本新引入的官方包管理工具用于解决之前没有地方记录依赖包具体版本的问题,方便依赖包的管理。(类似于 Java 的 pom.xml
文件)
查看一下 go.mod
文件
go.mod 提供了 module, require、replace 和 exclude 四个命令
- module 语句指定包的名字(路径)
- require 语句指定的依赖项模块
- replace 语句可以替换依赖项模块
- exclude 语句可以忽略依赖项模块
常用命令
go mod download
下载 go.mod 中的模块到本地缓存,缓存路径是 $GOPATH/pkg/mod/cachego mod edit
是提供了命令版编辑 go.mod 的功能,例如go mod edit -fmt go.mod
会格式化 go.modgo mod graph
把模块之间的依赖图显示出来go mod init
初始化模块(例如把原本 dep 管理的依赖关系转换过来),注意要在 init 后面加上项目名go mod tidy
增加缺失的包,移除没用的包go mod vendor
把依赖拷贝到 vendor/ 目录下go mod verify
确认依赖关系go mod why
解释为什么需要包和模块
显示依赖图可以直接使用 GoLand 提供的工具(就像 IDEA 那样的)
初始化项目
在任意文件夹创建项目
mkdir -p $HOME/als/project_name
指定 module 的根目录并生成 go.mod
文件
go mod init github.com/als/project_name
这将会生成模块配置文件 go.mod
,其中包含模块名称和版本。
module github.com/als/project_name
go 1.17
此 go.mod
文件定义 Module 的根,go 命令将相应地与包一起使用。
添加依赖
其实只需在文件中指明依赖的包,执行时会自动下载依赖
创建 main.go 文件
package main
import (
"github.com/gin-gonic/gin"
)
func main() {
r := gin.Default()
r.GET("/ping", func(c *gin.Context) {
c.JSON(200, gin.H{
"message": "pong",
})
})
r.Run() // listen and serve on 0.0.0.0:8080 (for windows "localhost:8080")
}
执行 go run main.go
运行代码会发现 go mod 会自动查找依赖自动下载
但是!在 go 1.16 版本后,运行 go 命令(go run, go build, go test
)时,如果 import 的依赖在 go.mod
文件中没有,不会再自动下载并修改 go.mod 和 go.sum 文件,而会提示错误,并需要手动执行 go get
命令下载对应的包。
go get github.com/gin-gonic/gin
原因是自动修复的方式不是在任何场景下都适用:如果导入的包在没有提供任何依赖的情况自动添加新依赖,则可能会引起公共依赖包的升级等。
添加完包后,可以通过使用 go list -m all
查看当前模块所依赖的包列表。
清理无用的依赖
go mod tidy
使用 vendor
使用 vendor 时如果需要下载依赖,需要临时开启 GO111MODULE
GO111MODULE=on go get github.com/gin-gonic/gin@master
go mod vendor
如果需要使用 vendor 打包则
GO111MODULE=on go run -mod=vendor .
更新依赖
更新依赖为指定版本依赖
运行 go get -u
将会升级到最新的次要版本或者修订版本(x.y.z, z是修订版本号, y是次要版本号)
运行 go get -u=patch
将会升级到最新的修订版本
运行 go get package@version
将会升级到指定的版本号 version
运行 go get
如果有版本的更改,那么 go.mod
文件也会更改
注意这个 -u
是打印下载细节的意思
go list -m -versions rsc.io/sampler
rsc.io/sampler v1.0.0 v1.2.0 v1.2.1 v1.3.0 v1.3.1 v1.99.99
go get rsc.io/sampler@v1.3.1
编译项目
随便创建一个 main.go 文件
package main
import "fmt"
func main() {
fmt.Println("Hello, World!")
}
运行 go build
构建项目,可以发现生成了 exe 文件
或者执行以下命令直接运行
go run main.go
编写完代码后执行 go mod tidy
会自动下载依赖的库,也会删除多余的库
如果想把项目安装到 GOPATH 里面则需要使用
go install
C 依赖库
编译好的项目丢到 Docker 容器(Alpine 镜像)里面执行时发现报错 not found ld-linux-x86-64.so.2
这是因为 Alpine 镜像缺少了这个 ld-linux-x86-64.so.2 动态链接库,解决方法如下:
mkdir /lib64
ln -s /lib/libc.musl-x86_64.so.1 /lib64/ld-linux-x86-64.so.2
或者直接在 Build 的时候就直接不依赖 C 的动态库链接
CGO_ENABLED=0 go build -o collect
配置私有库
环境变量 GOPRIVATE 用来控制 go 命令把哪些仓库看做是私有的仓库,这样的话,就可以跳过 proxy server 和校验检查,这个变量的值支持用逗号分隔,可以填写多个值,例如:
GOPRIVATE=*.corp.example.com,rsc.io/private
命令行设置:
go env -w GOPRIVATE=private.repo.com
这样 go 命令会把所有包含这个后缀的软件包,包括 git.corp.example.com/xyzzy , rsc.io/private
, 和 rsc.io/private/quux
都以私有仓库来对待。
若所有需要配置的私有仓库都存在于一个组织下,如 github 下的组织 org_name,则直接填写组织名即可:
GOPRIVATE=github.com/org_name
如果要更新不支持https协议的私有库,还需再做如下的配置。
go get -insecure
,但是很麻烦,每个包都需要手动在 go mod
下导入(go mod 是不支持 HTTP 的);
go env -w GOINSECURE=private.repo.com
,设置 GOINSECURE 参数,非常方便。仅在 go 1.14 后新加入。
Reference
Getting started with Go 官方文档 Go Modules Reference Go Modules设置私有库,以及支持HTTP的私有库操作 go mod使用 深入Go Module之go.mod文件解析 go mod常用命令 以及 常见问题